package controllers

import (
	"ExchangeApp/global"
	"ExchangeApp/models"
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"gorm.io/gorm"
	"net/http"
	"time"
)

// cacheKey 文章列表缓存键
var cacheKey = "articles"

// CreateArticle 创建文章
// @Summary 创建新文章
// @Description 创建一篇新文章并更新缓存
// @Tags 文章
// @Accept json
// @Produce json
// @Param article body models.Article true "文章信息"
// @Success 201 {object} models.Article
// @Failure 400 {object} map[string]interface{}
// @Failure 500 {object} map[string]interface{}
// @Router /articles [post]
func CreateArticle(ctx *gin.Context) {
	// 声明文章模型对象
	var article models.Article

	// 绑定请求体JSON数据到结构体
	if err := ctx.ShouldBindJSON(&article); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err})
		return
	}

	// 自动迁移文章表结构
	if err := global.Db.AutoMigrate(&article); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err})
		return
	}

	// 创建文章记录到数据库
	if err := global.Db.Create(&article).Error; err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"error": "创建文章失败: " + err.Error(),
		})
		return
	}

	// 删除文章列表缓存，保证下次查询时获取最新数据
	if err := global.RedisDb.Del(cacheKey).Err(); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"error": "缓存删除失败: " + err.Error(),
		})
		return
	}

	// 返回创建成功的文章信息
	ctx.JSON(http.StatusCreated, article)
}

// GetArticles 获取文章列表
// @Summary 获取文章列表
// @Description 优先从缓存获取文章列表，如果缓存不存在则从数据库查询并缓存
// @Tags 文章
// @Produce json
// @Success 200 {array} models.Article
// @Failure 500 {object} map[string]interface{}
// @Router /articles [get]
func GetArticles(ctx *gin.Context) {
	// 尝试从Redis缓存获取文章列表
	cachedData, err := global.RedisDb.Get(cacheKey).Result()
	if errors.Is(err, redis.Nil) {
		// 缓存不存在，需要从数据库查询
		var articles []models.Article
		if err := global.Db.Find(&articles).Error; err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"error": "查询文章列表失败",
			})
			return
		}

		// 将文章列表序列化为JSON
		articleJSON, err := json.Marshal(articles)
		if err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}

		// 将数据存入Redis缓存，设置10分钟过期时间
		if err := global.RedisDb.Set(cacheKey, articleJSON, 10*time.Minute).Err(); err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to set cache"})
			return
		}

		// 返回查询到的文章列表
		ctx.JSON(http.StatusOK, articles)
	} else if err != nil {
		// Redis查询出错
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	} else {
		// 缓存存在，解析缓存数据
		var articles []models.Article
		// 将Redis中的JSON字符串反序列化为结构体
		if err := json.Unmarshal([]byte(cachedData), &articles); err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"error": "Failed to parse cached data",
			})
			return
		}

		// 返回缓存中的文章列表
		ctx.JSON(http.StatusOK, articles)
	}
}

// GetArticlesByID 根据ID获取文章
// @Summary 根据ID获取文章详情
// @Description 根据文章ID查询单篇文章详情
// @Tags 文章
// @Produce json
// @Param id path string true "文章ID"
// @Success 200 {object} models.Article
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /articles/{id} [get]
func GetArticlesByID(ctx *gin.Context) {
	// 获取路径参数中的文章ID
	id := ctx.Param("id")
	// 声明文章模型变量
	var article models.Article

	// 根据ID查询文章
	if err := global.Db.Where("id = ?", id).First(&article).Error; err != nil {
		// 处理不同类型的错误
		if errors.Is(err, gorm.ErrRecordNotFound) {
			// 文章不存在
			ctx.JSON(http.StatusNotFound, gin.H{"error": "文章不存在"})
		} else {
			// 其他数据库错误
			ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		}
		return
	}

	// 返回查询到的文章信息
	ctx.JSON(http.StatusOK, article)
}
